<?php
namespace Lib;

use Lib\Stack\StackEntity;
use Lib\Stack\StackStorage;
/**
 * 
 */
class Stack extends \ArrayObject{
    private $_name;
    
    
    public function __construct($name){
        $this->setName($name);
    }
    
    /**
     * Add any element to stack
     * @param string $name Name of element in stack
     * @param mixed $entityBody Content will be placed in stack
     * @param int $priority  Priority of element in stack
     */
    public function addElement($name, $entityBody, $priority = 0){
        $entity = StackEntity::getInstance();
        $entity->setName($name);
        $entity->setBody($entityBody);
        $entity->setPriority($priority);
        $this->offsetSet($name, $entity);
    }
    
    /**
     * Removes elements specified by name from stack
     * @param mixed $name Name element will be removed
     * @return bool If element not founded returns FALSE
     */
    public function removeElement($name){
        if($this->hasElement($name)){
            $this->offsetUnset($name);
            return true;
        } else {
            return false;
        }
    }
    
    /**
     * Finds element in current stack
     * @param mixed $name Name of element to find
     * @return bool
     */
    public function hasElement($name){
        return $this->offsetExists($name);
    }

    /**
     * Get element specified by $name from stack
     * @param string  $name Name of element to return
     * @return Lib\StackEntity|bool
     */
    public function getElement($name){
        if($this->hasElement($name)){
            return $this->offsetGet($name);
        } else {
            return false;
        }
    }
    /**
     * Return specified or all elements from stack in order
     * @param array $names Names of elements of stack will be returned
     * @return \ArrayObject Array of Lib\StackEntity
     */
    public function getElements($names = array()){
        $elements = new \ArrayObject();
        if(Data::is_array_accessible($names)){
            if(count($names)){
                foreach ($names as $name) {
                    $element = $this->getElement($name);
                    if(false !== $element){
                        $elements->offsetSet($name, $element);
                    }
                }
            } else {
                foreach ($this as $name=> $element){
                    if(false !== $element){
                        $elements->offsetSet($name, $element);
                    }
                }
            }
        } else {
            $element = $this->getElement($names);
            if(false !== $element){
                $elements->offsetSet($names, $element);
            }
        }
        
        $elements = $this->_getOrdered($elements);
        return $elements;
    }
    
    
    private function _getOrdered(\ArrayObject $elements){
        $cmp = function($a, $b){
            if ($a->getPriority() == $b->getPriority()) {
                return 0;
            }
            return ($a->getPriority() > $b->getPriority()) ? -1 : 1;
        };

        if(count($elements) > 1){
            $elements->uasort($cmp);
        }

        return $elements;
   }
    
    /**
     * Get name of stack
     * @return string
     */
    public function getName(){
        return $this->_name;
    }
    
    /**
     * Set name of stack
     * @param string $name 
     */
    public function setName($name){
        $this->_name = $name;
    }
    
    /**
     * Check existence of element specified by name
     * @param string $name
     * @return bool 
     */
    public function hasName($name){
        return ($name == $this->getName());
    }
}

